# [FEAT] Report section-manifest model and resolver - #78
Merged
Conversation
This was referenced Aug 17, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First step of the report section-numbering refactor: a data-driven section manifest so headings, numbers, inclusion, and jump-nav stop being hand-typed and inconsistent across report pages. This PR is infrastructure only — the model and resolver plus unit tests. No page generator is wired to it yet, so no rendered output changes and there is no golden re-baseline. The grid pilot that consumes it follows on a later branch.
What's here
oceanarray/reports/_manifest.py(package-neutral — it names no variable, page, or science — so it is vendored byte-identical to the sister repos):Panel/Section/Expand/Profiledataclasses describing a page as an ordered list of sections, each naming panel ids that render figures or tables.Panel.kind("figure"/"html"/"table") — a discriminator so the eventual render macro applies|safeonly to markup panels and never to a base64 figure payload, keeping theautoescape=Trueboundary to one branch.Panel.slotaccepts astror actx -> strcallable, so a page that derives a panel's width from its aspect ratio can compute the slot at resolution time; the resolver calls it when callable.resolve(profile, ctx, panels)— one pass: spliceExpandentries, drop sections whoseapplies_tois false (collected into a not-applicable list), resolve each kept section's panels (aNonerender becomes a.warnstub; a kept section whose panels all returnNonekeeps its heading with one stub), then number the survivors — content sections1..N, appendix sectionsA... Numbering is compact (over the rendered subset), so an absent section leaves no gap; identity is the section id (a stable slug), not the integer.tests/unit/test_manifest.py— 18 tests covering flat/none numbering, appendix lettering rollover,Expandsplicing,applies_todropping to the not-applicable list,None-render stubs, the kept-but-empty case, silent panel omission,kindcarry-through, and callable-slot resolution.Why compact numbering
A gap (
1, 2, 4) reads as a rendering bug. Reserved numbering does not deliver stability either — inserting one section renumbers every downstream heading on every page and breaks every golden — whereas compaction leaves a page unchanged when a section it never had is added elsewhere. Cross-page comparability comes from the profile fixing the order (hydrography always before velocity) and from stable anchors, not from the integers.Tests
18 new unit tests, all passing; full suite green; ruff clean. No existing code touched, so nothing else moves.